﻿using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Text;
using PropertyExpression.ControllableQuery.Test.Queries;
using PropertyExpression.ControllableQuery.Test.Queries.StringBuilding;
using PropertyExpression.ControllableQuery.Test.Queries.T4;

namespace PropertyExpression.ControllableQuery.PropertyExpressionGenerator
{
    public class Program
    {
        public static void Main()
        {
            GenerateCode(
                typeof(IPublicationInfo), 
                typeof(IPublicationTypeInfo),
                typeof(IModelPublicationInfo),
                typeof(IPartLinkInfo),
                typeof(Test.IModelPublicationInfo));
        }

        private static void GenerateCode(params Type[] types)
        {
            var builder = new StringBuilder(
@"using System;
using System.Linq.Expressions;
using PropertyExpression.ControllableQuery.TypedReader;
");
            foreach (var type in types)
            {
                builder.Append(
@"
namespace " + type.Namespace + @"
{");
                var typeName = ToCSharp(type);
                builder.Append(@"
    public static class " + type.Name + @"DataReaderExtensions
    {");
                foreach (var propertyInfo in type.GetProperties())
                {
                    var pascalNotationPropertyName = ToPascalNotation(propertyInfo.Name);
                    var propertyType = ToCSharp(propertyInfo.PropertyType);
                    builder.Append(@"
        private static readonly Expression<Func<" + typeName + @", " + propertyType + @">> " + pascalNotationPropertyName + @" = _ => _." + propertyInfo.Name + @";
        public static " + propertyType + @" " + propertyInfo.Name + @"(this IDataReader<" + typeName + @"> it)
        {
            return it.GetValue(" + pascalNotationPropertyName + @");
        }
");
                }
                builder.Append(@"
    }
");
                builder.Append(@"}
");
            }

            var path = Path.Combine(
                typeof (Program).Assembly.Location,
                @"..\..\..\..\ControllableQuery.Test\PropertyExpressionExtensions.cs");
            var resultString = builder.ToString();
            if (resultString != File.ReadAllText(path))
            {
                File.WriteAllText(path, resultString);
            }
        }

        private static string ToPascalNotation(string propertyInfoName)
        {
            return propertyInfoName.Substring(0, 1).ToLower() + propertyInfoName.Substring(1);
        }

        private static string ToCSharp(Type type)
        {
            var stringBuilder = new StringBuilder();
            using (var stringWriter = new StringWriter(stringBuilder))
            {
                CodeDomProvider.CreateProvider("C#").GenerateCodeFromExpression(
                    new CodeTypeReferenceExpression(type), stringWriter, new CodeGeneratorOptions());
            }
            return stringBuilder.ToString();
        }
    }
}